#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef _WIN32
#include <windows.h>
#include <windowsx.h>
#else
#include <sys/time.h>
#include <time.h>
#include "unistd.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "randomc.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBrain.h"
#include "AWTracerBrain.h"
#include "AWThreadedBrain.h"
#include "AWNOOSBrain.h"
#include "AWNOOSExperimenterBrainCV.h"

#include "CaseBaseUtils.h"

#include "loader.h"



AW_NOOSExperimenterBrainCV::AW_NOOSExperimenterBrainCV(Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSBrain(O,Memory,CB,pause) 
{
	class_name->set("AW_NOOSExperimenterBrainCV");

	m_n_folds=10;
	m_n_iterations=5;
	m_percentage_to_distribute=1.0F;
	m_desired_bias = 0.0;
	m_problem_sort=new Symbol("sponge-problem");

	m_random=new TRanrotBGenerator(0);

} /* AW_NOOSExperimenterBrainCV::AW_NOOSExperimenterBrainCV */ 



AW_NOOSExperimenterBrainCV::AW_NOOSExperimenterBrainCV(FILE *fp,Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSBrain(O,Memory,CB,pause) 
{
	class_name->set("AW_NOOSExperimenterBrainCV");

	m_n_folds=10;
	m_n_iterations=5;
	m_percentage_to_distribute=1.0F;
	m_desired_bias = 0.0;
	m_problem_sort=new Symbol("sponge-problem");

	m_random=new TRanrotBGenerator(0);

	load(fp);
} /* AW_NOOSExperimenterBrainCV::AW_NOOSExperimenterBrainCV */ 


AW_NOOSExperimenterBrainCV::~AW_NOOSExperimenterBrainCV()
{
	if (m_random!=0) delete m_random;
	m_random=0;

	if (m_problem_sort!=0) delete m_problem_sort;
	m_problem_sort=0;

} /* AW_NOOSExperimenterBrainCV::~AW_NOOSExperimenterBrainCV */ 


bool AW_NOOSExperimenterBrainCV::load(FILE *fp) 
{
	if (!AW_NOOSBrain::load(fp)) return false;

	if (4!=fscanf(fp,"%i %i %f %f",&m_n_folds,&m_n_iterations,&m_percentage_to_distribute,&m_desired_bias)) return false;
	if (m_problem_sort!=0) delete m_problem_sort;
	m_problem_sort=new Symbol(fp);

	return true;
} /* AW_NOOSExperimenterBrainCV::load */ 


bool AW_NOOSExperimenterBrainCV::save(FILE *fp) 
{
	if (!AW_NOOSBrain::save(fp)) return false;

	fprintf(fp,"%i %i %g %g\n",m_n_folds,m_n_iterations,m_percentage_to_distribute,m_desired_bias);
	m_problem_sort->save(fp);

	return true;
} /* AW_NOOSExperimenterBrainCV::save */ 


bool AW_NOOSExperimenterBrainCV::is_a(char *c)
{
	if (strcmp(c,"AW_NOOSExperimenterBrainCV")==0) return true;

	return AW_NOOSBrain::is_a(c);
} /* AW_NOOSExperimenterBrainCV::is_a */ 


bool AW_NOOSExperimenterBrainCV::is_a(Symbol *c)
{
	if (c->cmp("AW_NOOSExperimenterBrainCV")) return true;

	return AW_NOOSBrain::is_a(c);
} /* AW_NOOSExperimenterBrainCV::is_a */ 


void AW_NOOSExperimenterBrainCV::thread(void)
{
	List<Symbol> agent_names,monitor_names;
	Symbol *agent_name;
	List<FeatureTerm> case_base;
	List<char> case_base_text;	/* cases converted to NOOS */ 
	List<FeatureTerm> *folds;
	List<FeatureTerm> training_set,test_set;
	FeatureTerm *f;
	int iteration,fold;

	int total_correct_answers=0;
	int total_incorrect_answers=0;
	int initial_time;

	folds=new List<FeatureTerm>[m_n_folds];

	/* Get the data set: */ 
	test_status();
	{
		char *s;
		FeatureTerm *c;
		List<FeatureTerm> *l;
		l=m_casebase->SearchFT(m_ontology->get_sort(m_problem_sort->get()));

		while(!l->EmptyP()) {
			c=l->ExtractIni();
			s=c->toStringNOOS(m_memory);
			case_base.Add(new FeatureTerm(c));
			case_base_text.Add(s);
		} /* while */  
		delete l;
	}
	write_debug_report("[Sync]: working with %i '%s' cases.\n",case_base.Length(),m_problem_sort->get());

	test_status();
	initial_time=GetTickCount();
	write_debug_report("[Sync]: starting experiments...\n");
	do {
		/* Get other agent's names: */ 
		test_status();
		pthread_mutex_lock(&m_sensor_data_mutex);
		m_sensor_data.Rewind();
		while(m_sensor_data.Iterate(f)) {						
			if (f->getSort()->is_a(m_ontology->get_sort("sensed-agent")) &&
				!f->getSort()->is_a(m_ontology->get_sort("sensed-self"))) {
				Symbol *name=f->featureValueQuick("name")->getSymbol();
				if (name->get()[0]=='L' &&
					name->get()[1]=='e' &&
					name->get()[2]=='a' &&
					name->get()[3]=='r' &&
					name->get()[4]=='n' &&
					name->get()[5]=='e' &&
					name->get()[6]=='r') {
					agent_names.Add(new Symbol(name));
				} /* if */ 
				if (name->get()[0]=='M' &&
					name->get()[1]=='o' &&
					name->get()[2]=='n' &&
					name->get()[3]=='i' &&
					name->get()[4]=='t' &&
					name->get()[5]=='o' &&
					name->get()[6]=='r') {
					monitor_names.Add(new Symbol(name));
				} /* if */ 
				
			} /* if */ 
		} /* while */ 
		pthread_mutex_unlock(&m_sensor_data_mutex);
		
		/* If there are no agents, then wait till there are some agents */ 
		if (agent_names.Length()==0) wait(100);

	}while(agent_names.Length()==0);	 

	write_debug_report("[Sync]: recognized %i learning agents.\n",agent_names.Length());

	for(iteration=0;iteration<m_n_iterations;iteration++) {
//	for(iteration=0;iteration<1;iteration++) {
		int iteration_correct_answers=0;
		int iteration_incorrect_answers=0;

		write_debug_report("[Sync]: started iteration %i -----------------------------\n",iteration+1);
		write_debug_report("[Sync]: Time: %g sec.\n",(GetTickCount()-initial_time)/1000.0F);
		
		{
			char tmp[256];
			FeatureTerm *op;

			sprintf(tmp,"Iteration %i:",iteration+1);
			monitor_names.Rewind();
			while(monitor_names.Iterate(agent_name)) {
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
				enqueue_operator(op);
			} /* while */ 	
		}

		/* Generate folds: */ 
		test_status();
		{
			int j;
			int cases_per_fold=0;
			FeatureTerm *c;
			List<FeatureTerm> tmp;

			tmp.Copy(case_base);

			cases_per_fold=case_base.Length()/m_n_folds;

			for(fold=0;fold<m_n_folds-1;fold++) {
				folds[fold].Delete();
				for(j=0;j<cases_per_fold;j++) {
					c=tmp[m_random->IRandom(0,tmp.Length()-1)];
					tmp.DeleteElement(c);
					folds[fold].Add(c);
				} /* for */ 
			} /* for */ 
			folds[m_n_folds-1].Delete();
			while(!tmp.EmptyP()) folds[m_n_folds-1].Add(tmp.ExtractIni());
			write_debug_report("[Sync]: folds created.\n");
			for(fold=0;fold<m_n_folds;fold++) {
				write_debug_report("[Sync]: fold %i: %i cases\n",fold,folds[fold].Length());
//				folds[fold].Rewind();
//				while(folds[fold].Iterate(c)) {
//					write_debug_report("%s\n",c->getName()->get());
//				} /* while */ 
			} /* for */ 
		}

		for(fold=0;fold<m_n_folds;fold++) {
//		for(fold=0;fold<1;fold++) {

			write_debug_report("[Sync]: started fold %i of iteration %i-----------------------------\n",fold+1,iteration+1);

			/* Partition data-set in test and training set: */ 
			test_status();
			{
				int j;
				FeatureTerm *c;

				training_set.Delete();
				test_set.Delete();

				for(j=0;j<m_n_folds;j++) {
					if (j==fold) {
						folds[j].Rewind();
						while(folds[j].Iterate(c)) test_set.Add(new FeatureTerm(c));
					} else {
						folds[j].Rewind();
						while(folds[j].Iterate(c)) training_set.Add(new FeatureTerm(c));
					} /* if */  
				} /* for */ 
				test_set.Randomize();
				training_set.Randomize();
				write_debug_report("[Sync]: training set created: %i cases.\n",training_set.Length());
				write_debug_report("[Sync]: test set created: %i cases.\n",test_set.Length());
			}

			{
				/* Set the color of the agent to "starting fold": */ 
				FeatureTerm *op;
				op=FeatureTerm::fromStringNOOS("(define (color-operator) (r 0.4) (g 0.4) (b 1.0))",m_memory,m_ontology);
				enqueue_operator(op);
			}

			/* Distribute the training set: */ 
			test_status();
			{
				int i;
				FeatureTerm *c;
				FeatureTerm *op;
				AW_Message *m;
				char *str;
				List <FeatureTerm> *distribution;

				{
					FeatureTerm *op;
					char tmp[256];
					sprintf(tmp,"(define (status-operator) (text \"training\"))");
					op=FeatureTerm::fromStringNOOS(tmp,m_memory,m_ontology);
					enqueue_operator(op);
				}

				distribution=new List<FeatureTerm>[agent_names.Length()];

				splitTrainingSet(distribution,&training_set,agent_names.Length(),m_percentage_to_distribute,m_desired_bias);

				for(i=0;i<agent_names.Length();i++) {
					agent_name=agent_names[i];

					{
						int j;
						char *prefix="(define (learn-message) (case ";
						char *sufix=" ))";
						int len=1+strlen(prefix)+strlen(sufix);

						distribution[i].Rewind();
						while(distribution[i].Iterate(c)) {
							j=case_base.Position(c);
							len+=strlen(case_base_text[j])+1;
						} /* while */ 

						str=new char[len];
						sprintf(str,prefix);
						distribution[i].Rewind();
						while(distribution[i].Iterate(c)) {
							j=case_base.Position(c);
							strcat(str,case_base_text[j]);
							strcat(str," ");
						} /* while */ 
						strcat(str,sufix);

						distribution[i].Delete();
					}

					op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
									   "receiver",new FeatureTerm(0,
																  new Symbol(agent_name),
																  m_ontology),
									   "content",new FeatureTerm(0,
																  new Symbol(str),
																  m_ontology));
					delete []str;

					enqueue_operator(op);
					write_debug_report("[Sync]: cases sent to %s.\n",agent_name->get());
				} /* for */ 

				for(i=0;i<agent_names.Length();i++) {
					/* Wait for the confirmation of the agent: */ 
					wait_message();
					m=get_message();
//					write_debug_report("[Sync]: received confirmation from %s [%i confirmations remaining]\n",m->sender->get(),agent_names.Length()-(i+1));
					delete m;
				} /* for */ 

				delete []distribution;
			}

			{
				/* Set the color of the agent to "waiting": */ 
				FeatureTerm *op;
				op=FeatureTerm::fromStringNOOS("(define (color-operator) (r 1.0) (g 1.0) (b 1.0))",m_memory,m_ontology);
				enqueue_operator(op);
			}

			/* Send the test set: */ 
			test_status();
			{
				Symbol *agent_name;
				FeatureTerm *c,*msg,*op;
				char *str;
				AW_Message *m;
				int correct_answers=0,incorrect_answers=0;
				int test_cases_sent=0;

				test_set.Rewind();
				while(test_set.Iterate(c)) {
//				{	c = test_set[0];

					{
						FeatureTerm *op;
						char tmp[256];
						sprintf(tmp,"(define (status-operator) (text \"test %i/%i\"))",test_cases_sent,test_set.Length());
						op=FeatureTerm::fromStringNOOS(tmp,m_memory,m_ontology);
						enqueue_operator(op);
					}


					/* Send the problem: */ 
					agent_name=agent_names[m_random->IRandom(0,agent_names.Length()-1)];
					msg=new FeatureTerm((char *)0,m_ontology->get_sort("request-prediction-message"),1,
										"problem",get_description(c));

					str=msg->toStringNOOS(m_memory);
					op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
									   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
									   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
					delete []str;
					delete msg;

					enqueue_operator(op);
					write_debug_report("[Sync]: test case sent to %s.\n",agent_name->get());


					/* Wait for the answer of the agent: */ 
					wait_message();
					m=get_message();
//					write_debug_report("[Sync]: received answer from %s\n",m->sender->get());

					/* Check whether the answer is correct: */ 
					{
						FeatureTerm *correct,*answer,*prediction=0;						
						char *s,*s2;

						correct=get_solution(c);

						answer=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
						prediction=answer->featureValue("solution");

						if (prediction!=0) {
							s=correct->toStringNOOS(m_memory);
							s2=prediction->toStringNOOS(m_memory);
							write_debug_report("[Sync]: [%s][%s] %s -> %s \n",c->getName()->get(),(*prediction==*correct ? "correct":"incorrect"),s,s2);
							delete []s;
							delete []s2;

							if (*prediction==*correct) {
								correct_answers++;
							} else {
								incorrect_answers++;
							} /* if */ 
							delete prediction;
						} else {
							s=correct->toStringNOOS(m_memory);
							write_debug_report("[Sync]: %s -> -\n",s);
							delete []s;
							incorrect_answers++;
						} /* if */ 

						delete answer;
						delete correct;
					}
					delete m;

					/* Send the agent the correct solution, so that it can perform the retain process: */ 
					{
						msg=new FeatureTerm((char *)0,m_ontology->get_sort("solution-inform-message"),1,
											"solution",get_solution(c));

						str=msg->toStringNOOS(m_memory);
						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
										   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
						delete []str;
						delete msg;

						enqueue_operator(op);
					}

					/* Wait for the answer of the agent: */ 
					wait_message();
					m=get_message();
//					write_debug_report("[Sync]: received answer from %s\n",m->sender->get());
					write_debug_report("[Sync]: ---- next problem ---- \n\n\n",m->sender->get());

					test_cases_sent++;

					delete m;
				} /* while */ 

				{
					char tmp[256];
					sprintf(tmp,"Fold %i: %i/%i (%g%%)",
								fold+1,
								correct_answers,correct_answers+incorrect_answers,
								(correct_answers+incorrect_answers==0 ? 0:float(100*correct_answers)/float(correct_answers+incorrect_answers)));
					write_debug_report("[Sync]: %s\n",tmp);

					monitor_names.Rewind();
					while(monitor_names.Iterate(agent_name)) {
						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
										   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
						enqueue_operator(op);
					} /* while */ 					 
				}
				iteration_correct_answers+=correct_answers;
				iteration_incorrect_answers+=incorrect_answers;
			}

			/* Clear the case bases of the agents: */ 
			{
				int i;
				FeatureTerm *op;
				FeatureTerm *msg;
				Symbol *agent_name;
				AW_Message *m;
				char *str;

				for(i=0;i<agent_names.Length();i++) {
					agent_name=agent_names[i];

					msg=new FeatureTerm((char *)0,m_ontology->get_sort("forget-message"),0);
					str=msg->toStringNOOS(m_memory);
					op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
									   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
									   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
					delete []str;
					delete msg;

					enqueue_operator(op);

					write_debug_report("[Sync]: forget message sent to %s.\n",agent_name->get());
				} /* for */ 

				for(i=0;i<agent_names.Length();i++) {
					/* Wait for the confirmation of the agent: */ 
					wait_message();
					m=get_message();
//					write_debug_report("[Sync]: received confirmation from %s [%i confirmations remaining]\n",m->sender->get(),agent_names.Length()-(i+1));
					delete m;
				} /* for */ 
			}
	
			wait(1);
		} /* for */ 

		{
			char tmp[256];
			FeatureTerm *op;

			sprintf(tmp,"Iteration %i: %i/%i (%g%%)",
						 iteration+1,
 					     iteration_correct_answers,iteration_correct_answers+iteration_incorrect_answers,
						 (iteration_correct_answers+iteration_incorrect_answers==0 ? 0:float(100*iteration_correct_answers)/float(iteration_correct_answers+iteration_incorrect_answers)));
			write_debug_report("[Sync]: %s\n",tmp);

			monitor_names.Rewind();
			while(monitor_names.Iterate(agent_name)) {
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
				enqueue_operator(op);
			} /* while */ 
			total_correct_answers+=iteration_correct_answers;
			total_incorrect_answers+=iteration_incorrect_answers;
		}
	} /* for */ 


	{
		char tmp[256];
		FeatureTerm *op;

		sprintf(tmp,"Total Accuracy: %i/%i (%g%%)",
					total_correct_answers,total_correct_answers+total_incorrect_answers,
					(total_correct_answers+total_incorrect_answers==0 ? 0:float(100*total_correct_answers)/float(total_correct_answers+total_incorrect_answers)));
		write_debug_report("[Sync]: %s\n",tmp);
		write_debug_report("[Sync]: experiments finished.\n");
		write_debug_report("[Sync]: Time: %g sec.\n",(GetTickCount()-initial_time)/1000.0F);

		monitor_names.Rewind();
		while(monitor_names.Iterate(agent_name)) {
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(tmp),m_ontology));
			enqueue_operator(op);
		} /* while */ 				
	}

	delete []folds;

	{
		/* Kill SYC agent: */ 
		FeatureTerm *op;
		op=FeatureTerm::fromStringNOOS("(define (suicide-operator))",m_memory,m_ontology);
		enqueue_operator(op);
	}

} /* AW_NOOSExperimenterBrainCV::thread */ 


void AW_NOOSExperimenterBrainCV::splitTrainingSet(List <FeatureTerm> *distribution,List<FeatureTerm> *training_set,int nagents,float percentage_to_distribute,double bias)
{
	TRanrotBGenerator *random=new TRanrotBGenerator(0);

	// Get List of solutions:
	List<FeatureTerm> solutions;
	int i,j,k;
	int *global_count,*reduced_count;
	FeatureTerm *f,*s,*s2;
	bool found;

	training_set->Rewind();
	while(training_set->Iterate(f)) {
		s = get_solution(f);
		solutions.Rewind();
		found = false;
		while(solutions.Iterate(s2) && !found) if (s->equivalents(s2)) found=true;
		if (!found) solutions.Add(new FeatureTerm(s));
	} // while 

	int total_to_distribute=0;
	total_to_distribute=int(training_set->Length()*percentage_to_distribute);

	write_debug_report("[Sync]: splitTrainingSet %i among %i agents, %i classes, percentage: %g (%i), bias: %g\n",training_set->Length(),nagents,solutions.Length(),percentage_to_distribute,total_to_distribute,bias);

	global_count = new int[solutions.Length()];
	reduced_count = new int[solutions.Length()];
	for(i=0;i<solutions.Length();i++) {
		global_count[i]=0;
		reduced_count[i]=0;
	} // wfor

	// Count the number of cases of each solution:
	training_set->Rewind();
	while(training_set->Iterate(f)) {
		s = get_solution(f);
		solutions.Rewind();
		i=0;
		found = false;
		while(solutions.Iterate(s2) && !found) {
			if (s->equivalents(s2)) {
				found=true;
				global_count[i]++;
			} // if
			i++;
		} // while
	} // while 

	i=0;
	solutions.Rewind();
	while(solutions.Iterate(s2)) {

		reduced_count[i] = int((global_count[i]*percentage_to_distribute)+0.5);

		char *s=s2->toStringNOOS(0);
		write_debug_report("[Sync]: solution: %s - %i (reduced: %i)\n",s,global_count[i],reduced_count[i]);
		delete []s;
		i++;
	} // while

	// Generate distributions with the desired bias:
	double **dist= new double*[nagents];
	int **agent_count= new int*[nagents];
	for(i=0;i<nagents;i++) {
		dist[i]= generateBiasedDistribution(solutions.Length(),bias,random);
		agent_count[i]=new int[solutions.Length()];
		for(j=0;j<solutions.Length();j++) agent_count[i][j]=0;
	} // for

	while(!training_set->EmptyP()) {		
		f = training_set->operator [](random->IRandom(0,training_set->Length()-1));
		s = get_solution(f);
		solutions.Rewind();
		i=0;
		found = false;
		while(solutions.Iterate(s2) && !found) {
			if (s->equivalents(s2)) {
				found=true;
				global_count[i]++;
			} else i++;
		} // while

		double total = 0;
		for(j=0;j<nagents;j++) total+=dist[j][i];

		if (reduced_count[i]>=0) {
			double v = random->Random()*total;
			double accum=0;

			k=-1;
			found = false;
			for(j=0;j<nagents && !found;j++) {
				accum+=dist[j][i];
				if (accum>=v) {
					k=j;
					found= true;
				} // if
			} // for
			if(k==-1) k=nagents-1;

//			write_debug_report("[Sync]: solution %i for agent %i (%g,%g)\n",i,k,total,v);

			agent_count[k][i]++;
		
			distribution[k].Add(f);

			reduced_count[i]--;
			training_set->DeleteElement(f);		
		} else {
			training_set->DeleteElement(f);		
			delete f;
		} // if
		
	} // for 

	for(i=0;i<nagents;i++) {
		write_debug_report("[Sync]: count for agent %i: ",i);
		for(j=0;j<solutions.Length();j++) write_debug_report("%i ",agent_count[i][j]);
		write_debug_report("\n");
		delete []dist[i];
		dist[i]=0;
		delete []agent_count[i];
		agent_count[i]=0;
	} // for

} /* AW_NOOSExperimenterBrainCV::splitTrainingSet */ 


double *AW_NOOSExperimenterBrainCV::generateBiasedDistribution(int nclasses, double desiredBias,TRanrotBGenerator *random) 
{
	double *dist = new double[nclasses], *dist2 = new double[nclasses];
	double bias,bias2,total;
	int i,j,k;

	total=0;
	for(i=0;i<nclasses;i++) {
		dist[i]=random->Random();
		total+=dist[i];
	} // for
	for(i=0;i<nclasses;i++) dist[i]/=total;

	for(k=0;k<10000;k++) {
		bias = 0;
		for(i=0;i<nclasses;i++) bias+=(dist[i]-(1.0/nclasses))*(dist[i]-(1.0/nclasses));
		bias = sqrt(bias);

		for(j=0;j<nclasses;j++) {
			total=0;
			for(i=0;i<nclasses;i++) {
				dist2[i]=dist[i];
				if (i==j && dist2[i]<1.0) dist2[i]+=0.05*random->Random();	
				if (dist2[i]>1.0) dist2[i]=1.0;
				total+=dist2[i];
			} // for
			for(i=0;i<nclasses;i++) dist2[i]/=total;
			bias2 = 0;
			for(i=0;i<nclasses;i++) bias2+=(dist2[i]-(1.0/nclasses))*(dist2[i]-(1.0/nclasses));
			bias2 = sqrt(bias2);

			if (fabs(bias2-desiredBias)<fabs(bias-desiredBias)) {
				for(i=0;i<nclasses;i++) dist[i]=dist2[i];
				bias=bias2;
			} // if

			total=0;
			for(i=0;i<nclasses;i++) {
				dist2[i]=dist[i];
				if (i==j && dist2[i]>0.0) dist2[i]-=0.05*random->Random();	
				if (dist2[i]<0) dist2[i]=0;
				total+=dist2[i];
			} // for
			for(i=0;i<nclasses;i++) dist2[i]/=total;
			bias2 = 0;
			for(i=0;i<nclasses;i++) bias2+=(dist2[i]-(1.0/nclasses))*(dist2[i]-(1.0/nclasses));
			bias2 = sqrt(bias2);

			if (fabs(bias2-desiredBias)<fabs(bias-desiredBias)) {
				for(i=0;i<nclasses;i++) dist[i]=dist2[i];
			} // if
		} // for

//		write_debug_report("[Sync]: bias: %g  [%i]\n",bias,k);
	} // for

	write_debug_report("[Sync]: distribution: ");
	for(i=0;i<nclasses;i++) write_debug_report("%g ",dist[i]);
	write_debug_report(" -> bias: %g\n",bias);

	delete []dist2;

	return dist;
} // AW_NOOSExperimenterBrainCV::generateBiasedDistribution


